/**
Unicode Properties and Values and Aliases
Property Script_Extensions values list is same as Script
*/

export type RawAliasDataMap = {[k1: string]: {[k2: string]: string}};

/**
Raw data of properties and values aliases.
Multi aliases are comma separated
*/
export const RawAliasData = {
  NonBinary_Property: {
    General_Category: 'gc',
    Script: 'sc',
    Script_Extensions: 'scx'
  },
  Binary_Property: {
    ASCII: '',
    ASCII_Hex_Digit: 'AHex',
    Alphabetic: 'Alpha',
    Any: '',
    Assigned: '',
    Bidi_Control: 'Bidi_C',
    Bidi_Mirrored: 'Bidi_M',
    Case_Ignorable: 'CI',
    Cased: '',
    Changes_When_Casefolded: 'CWCF',
    Changes_When_Casemapped: 'CWCM',
    Changes_When_Lowercased: 'CWL',
    Changes_When_NFKC_Casefolded: 'CWKCF',
    Changes_When_Titlecased: 'CWT',
    Changes_When_Uppercased: 'CWU',
    Dash: '',
    Default_Ignorable_Code_Point: 'DI',
    Deprecated: 'Dep',
    Diacritic: 'Dia',
    Emoji: '',
    Emoji_Component: '',
    Emoji_Modifier: '',
    Emoji_Modifier_Base: '',
    Emoji_Presentation: '',
    Extender: 'Ext',
    Grapheme_Base: 'Gr_Base',
    Grapheme_Extend: 'Gr_Ext',
    Hex_Digit: 'Hex',
    IDS_Binary_Operator: 'IDSB',
    IDS_Trinary_Operator: 'IDST',
    ID_Continue: 'IDC',
    ID_Start: 'IDS',
    Ideographic: 'Ideo',
    Join_Control: 'Join_C',
    Logical_Order_Exception: 'LOE',
    Lowercase: 'Lower',
    Math: '',
    Noncharacter_Code_Point: 'NChar',
    Pattern_Syntax: 'Pat_Syn',
    Pattern_White_Space: 'Pat_WS',
    Quotation_Mark: 'QMark',
    Radical: '',
    Regional_Indicator: 'RI',
    Sentence_Terminal: 'STerm',
    Soft_Dotted: 'SD',
    Terminal_Punctuation: 'Term',
    Unified_Ideograph: 'UIdeo',
    Uppercase: 'Upper',
    Variation_Selector: 'VS',
    White_Space: 'space',
    XID_Continue: 'XIDC',
    XID_Start: 'XIDS'
  },
  General_Category: {
    Cased_Letter: 'LC',
    Close_Punctuation: 'Pe',
    Connector_Punctuation: 'Pc',
    Control: 'Cc,cntrl',
    Currency_Symbol: 'Sc',
    Dash_Punctuation: 'Pd',
    Decimal_Number: 'Nd,digit',
    Enclosing_Mark: 'Me',
    Final_Punctuation: 'Pf',
    Format: 'Cf',
    Initial_Punctuation: 'Pi',
    Letter: 'L',
    Letter_Number: 'Nl',
    Line_Separator: 'Zl',
    Lowercase_Letter: 'Ll',
    Mark: 'M,Combining_Mark',
    Math_Symbol: 'Sm',
    Modifier_Letter: 'Lm',
    Modifier_Symbol: 'Sk',
    Nonspacing_Mark: 'Mn',
    Number: 'N',
    Open_Punctuation: 'Ps',
    Other: 'C',
    Other_Letter: 'Lo',
    Other_Number: 'No',
    Other_Punctuation: 'Po',
    Other_Symbol: 'So',
    Paragraph_Separator: 'Zp',
    Private_Use: 'Co',
    Punctuation: 'P,punct',
    Separator: 'Z',
    Space_Separator: 'Zs',
    Spacing_Mark: 'Mc',
    Surrogate: 'Cs',
    Symbol: 'S',
    Titlecase_Letter: 'Lt',
    Unassigned: 'Cn',
    Uppercase_Letter: 'Lu'
  },
  Script: {
    Adlam: 'Adlm',
    Ahom: 'Ahom',
    Anatolian_Hieroglyphs: 'Hluw',
    Arabic: 'Arab',
    Armenian: 'Armn',
    Avestan: 'Avst',
    Balinese: 'Bali',
    Bamum: 'Bamu',
    Bassa_Vah: 'Bass',
    Batak: 'Batk',
    Bengali: 'Beng',
    Bhaiksuki: 'Bhks',
    Bopomofo: 'Bopo',
    Brahmi: 'Brah',
    Braille: 'Brai',
    Buginese: 'Bugi',
    Buhid: 'Buhd',
    Canadian_Aboriginal: 'Cans',
    Carian: 'Cari',
    Caucasian_Albanian: 'Aghb',
    Chakma: 'Cakm',
    Cham: 'Cham',
    Cherokee: 'Cher',
    Common: 'Zyyy',
    Coptic: 'Copt,Qaac',
    Cuneiform: 'Xsux',
    Cypriot: 'Cprt',
    Cyrillic: 'Cyrl',
    Deseret: 'Dsrt',
    Devanagari: 'Deva',
    Duployan: 'Dupl',
    Egyptian_Hieroglyphs: 'Egyp',
    Elbasan: 'Elba',
    Ethiopic: 'Ethi',
    Georgian: 'Geor',
    Glagolitic: 'Glag',
    Gothic: 'Goth',
    Grantha: 'Gran',
    Greek: 'Grek',
    Gujarati: 'Gujr',
    Gurmukhi: 'Guru',
    Han: 'Hani',
    Hangul: 'Hang',
    Hanunoo: 'Hano',
    Hatran: 'Hatr',
    Hebrew: 'Hebr',
    Hiragana: 'Hira',
    Imperial_Aramaic: 'Armi',
    Inherited: 'Zinh,Qaai',
    Inscriptional_Pahlavi: 'Phli',
    Inscriptional_Parthian: 'Prti',
    Javanese: 'Java',
    Kaithi: 'Kthi',
    Kannada: 'Knda',
    Katakana: 'Kana',
    Kayah_Li: 'Kali',
    Kharoshthi: 'Khar',
    Khmer: 'Khmr',
    Khojki: 'Khoj',
    Khudawadi: 'Sind',
    Lao: 'Laoo',
    Latin: 'Latn',
    Lepcha: 'Lepc',
    Limbu: 'Limb',
    Linear_A: 'Lina',
    Linear_B: 'Linb',
    Lisu: 'Lisu',
    Lycian: 'Lyci',
    Lydian: 'Lydi',
    Mahajani: 'Mahj',
    Malayalam: 'Mlym',
    Mandaic: 'Mand',
    Manichaean: 'Mani',
    Marchen: 'Marc',
    Masaram_Gondi: 'Gonm',
    Meetei_Mayek: 'Mtei',
    Mende_Kikakui: 'Mend',
    Meroitic_Cursive: 'Merc',
    Meroitic_Hieroglyphs: 'Mero',
    Miao: 'Plrd',
    Modi: 'Modi',
    Mongolian: 'Mong',
    Mro: 'Mroo',
    Multani: 'Mult',
    Myanmar: 'Mymr',
    Nabataean: 'Nbat',
    New_Tai_Lue: 'Talu',
    Newa: 'Newa',
    Nko: 'Nkoo',
    Nushu: 'Nshu',
    Ogham: 'Ogam',
    Ol_Chiki: 'Olck',
    Old_Hungarian: 'Hung',
    Old_Italic: 'Ital',
    Old_North_Arabian: 'Narb',
    Old_Permic: 'Perm',
    Old_Persian: 'Xpeo',
    Old_South_Arabian: 'Sarb',
    Old_Turkic: 'Orkh',
    Oriya: 'Orya',
    Osage: 'Osge',
    Osmanya: 'Osma',
    Pahawh_Hmong: 'Hmng',
    Palmyrene: 'Palm',
    Pau_Cin_Hau: 'Pauc',
    Phags_Pa: 'Phag',
    Phoenician: 'Phnx',
    Psalter_Pahlavi: 'Phlp',
    Rejang: 'Rjng',
    Runic: 'Runr',
    Samaritan: 'Samr',
    Saurashtra: 'Saur',
    Sharada: 'Shrd',
    Shavian: 'Shaw',
    Siddham: 'Sidd',
    SignWriting: 'Sgnw',
    Sinhala: 'Sinh',
    Sora_Sompeng: 'Sora',
    Soyombo: 'Soyo',
    Sundanese: 'Sund',
    Syloti_Nagri: 'Sylo',
    Syriac: 'Syrc',
    Tagalog: 'Tglg',
    Tagbanwa: 'Tagb',
    Tai_Le: 'Tale',
    Tai_Tham: 'Lana',
    Tai_Viet: 'Tavt',
    Takri: 'Takr',
    Tamil: 'Taml',
    Tangut: 'Tang',
    Telugu: 'Telu',
    Thaana: 'Thaa',
    Thai: 'Thai',
    Tibetan: 'Tibt',
    Tifinagh: 'Tfng',
    Tirhuta: 'Tirh',
    Ugaritic: 'Ugar',
    Vai: 'Vaii',
    Warang_Citi: 'Wara',
    Yi: 'Yiii',
    Zanabazar_Square: 'Zanb'
  }
};

/** Map alias to canonical name */
export const aliasMap: Map<string, string> = buildAliasMap();

let scriptValues = readKeysToSet('Script');

/** Canonical Property Names and Values */
export const canonical = {
  NonBinary_Property: readKeysToSet('NonBinary_Property'),
  Binary_Property: readKeysToSet('Binary_Property'),
  General_Category: readKeysToSet('General_Category'),
  Script: scriptValues,
  Script_Extensions: scriptValues
};

let scriptAliases = readAliasesToSet('Script');

/** Aliases of each property value */
export const aliases = {
  NonBinary_Property: readAliasesToSet('NonBinary_Property'),
  Binary_Property: readAliasesToSet('Binary_Property'),
  General_Category: readAliasesToSet('General_Category'),
  Script: scriptAliases,
  Script_Extensions: scriptAliases
};

function buildAliasMap() {
  let mapping: Map<string, string> = new Map();
  let data = RawAliasData as RawAliasDataMap;
  for (let k in data) {
    for (let cname in data[k]) {
      let aliases = data[k][cname];
      if (aliases) {
        for (let alias of aliases.split(',')) {
          mapping.set(alias, cname);
        }
      }
    }
  }
  return mapping;
}

function readKeysToSet<K extends keyof typeof RawAliasData>(k: K) {
  return new Set(Object.keys((RawAliasData as RawAliasDataMap)[k]));
}

function readAliasesToSet<K extends keyof typeof RawAliasData>(k: K) {
  return new Set(
    Object.values((RawAliasData as RawAliasDataMap)[k])
      .map(s => s.split(','))
      .reduce((a, b) => a.concat(b), [])
  );
}
